#include "Merger.hpp"
#include <algorithm>

void	Merger::execute() EXC_THROWER()
{
	EXC_RETHROW_BEGIN()
	{
		unsigned	merged_tournee = 0;
		unsigned	i = 0;
		unsigned	k = 0;
		
		meSolution.clear();

		// insertion
		//std::cout << "insertion" << std::endl;
		
		// 
		
		random_shuffle(meTable.begin(), meTable.end());
        for (i = 0 ; i < meTable.size() ; i++)
        {
            meSolution[i].insertClient(Tournee::INSERT_BEGIN, meTable[i]);
            meSolution.validateTournee(i);
        }
		//std::cout << "complete" << std::endl;
		
		// complete solution
		if (!meSolution.isComplete())
			meSolution.complete();
		
		i = 0;
		
		//std::cout << "core" << std::endl;

		for (k = 1 ; k < 8 ; k++)
		{
			for (unsigned i = 0 ; i < 100 ; i += (1 << k))
			{
				//std::cout << meSolution.toString() << std::endl;
				
				
				TourneeEvalResult	left_eval;
				TourneeEvalResult	right_eval;
				
				//std::cout << "left : " << i + 0 << std::endl;
				//std::cout << "right : " << (i + ((k == 0) ? 1 : (1 << (k - 1)))) << std::endl;
				
				if ((i + ((k == 0) ? 1 : (1 << (k - 1)))) >= 100)
					break;
				
				Tournee&	left = meSolution[i + 0];
				Tournee&	right = meSolution[i + ((k == 0) ? 1 : (1 << (k - 1)))];
				
				Tournee		tmpleft(soVRPTW, 0);
				
				tmpleft.append(left);
				
				//std::cout << meSolution.toString() << std::endl;
				//std::cout << tmpleft.toString() << std::endl;
				//std::cout << "left : " << left.toString() << std::endl;
				//std::cout << "right : " << right.toString() << std::endl;
				
				left.append(right);
				right.append(tmpleft);
				
				left.eval(&left_eval);
				right.eval(&right_eval);
				
				if (left_eval.erValable)
				{
					if (right_eval.erValable)
					{
						if (left_eval.erTotalTime < right_eval.erTotalTime)
						{
							right.clear();
							meSolution.validateTournee(i + ((k == 0) ? 1 : (1 << (k - 1))));
							meSolution.validateTournee(i);
						}
						else
						{
							left.clear();
							left.append(right);
							right.clear();
							meSolution.validateTournee(i + ((k == 0) ? 1 : (1 << (k - 1))));
							meSolution.validateTournee(i);
						}
						
						meSolution.validateTournee(i + ((k == 0) ? 1 : (1 << (k - 1))));
						meSolution.validateTournee(i);
					}
					else
					{
							right.clear();
							meSolution.validateTournee(i + ((k == 0) ? 1 : (1 << (k - 1))));
							meSolution.validateTournee(i);
					}
				}
				else
				{
					if (right_eval.erValable)
					{
						left.clear();
						left.append(right);
						right.clear();
						meSolution.validateTournee(i + ((k == 0) ? 1 : (1 << (k - 1))));
						meSolution.validateTournee(i);
					}
					else
					{	
						//std::cout << "no merge possible" << std::endl;
						// faire la comparaison entre les deux
						// la plus legere prend la place du noeud actuel
						// et l'autre passe de l'autre cote
						meSolution.restoreTournee(i + ((k == 0) ? 1 : (1 << (k - 1))));
						meSolution.restoreTournee(i);
						
						//std::cout << "no merge possible" << std::endl;
						//std::cout << "left eval" << std::endl;
						left.eval(&left_eval);
						//std::cout << "right eval" << std::endl;
						right.eval(&right_eval);
						
						if (left_eval.erTotalTime < right_eval.erTotalTime)
						{
							//std::cout << "std case" << std::endl;
							meSolution.restoreTournee(i + ((k == 0) ? 1 : (1 << (k - 1))));
							meSolution.restoreTournee(i);	
						}
						else
						{
							//std::cout << "revert case" << std::endl;
							meSolution.swapTournees(i, i + ((k == 0) ? 1 : (1 << (k - 1))));
							meSolution.validateTournee(i);
							meSolution.validateTournee(i + ((k == 0) ? 1 : (1 << (k - 1))));
						}
					}
				}
				
				//std::cout << "RESULT : " << left.toString() << std::endl;
			}
		}
		
		//meSolution.reorganize();
        //std::cout << meSolution.toString() << std::endl;
		soBestSolution = &meSolution;
	}
	EXC_RETHROW_END()
}
